<template>
    <div>
        <el-popover placement="top-start" :width="185" trigger="click" :visible="visible">
            <template #reference>
                <div @click="recOpen">
                    <SvgIcon name="audio" width="1.8rem" height="1.8rem"></SvgIcon>
                </div>
            </template>
            <div style="padding-top: 5px">
                <!-- 波形绘制区域 -->
                <div class="recWave" ref="recwave"></div>
            </div>
            <!--el-progress :percentage="percentage" :format="format" /-->
            <el-button @click="recCancle">取消</el-button>
            <el-button type="primary" @click="sendVoice">发送语音</el-button>
        </el-popover>
    </div>
</template>

<script setup lang="ts">
import { ref, watch, reactive } from 'vue'
import { ElMessage } from 'element-plus'
import { v4 } from 'uuid'
import Recorder from 'recorder-core'
//引入mp3格式支持文件；如果需要多个格式支持，把这些格式的编码引擎js文件放到后面引入进来即可
//import 'recorder-core/src/engine/mp3';
//import 'recorder-core/src/engine/mp3-engine';
//录制wav格式的录音
import 'recorder-core/src/engine/wav'
//波形可视化插件
import 'recorder-core/src/extensions/waveview'

import useWebSocketStore from '@/store/modules/wschat'
import useUserStore from '@/store/modules/user'
import useMessagesStore from '@/store/modules/messages'
import { save } from '@/utils/savemessage'
import type { messageFormData } from '@/api/messages/type'
import { saveFile, readBlobAsBase64 } from '@/utils/chatfile'

const webSocketStore = useWebSocketStore()
const userStore = useUserStore()
const messagesStore = useMessagesStore()

let visible = ref<boolean>(false)
//用户是否发送语音消息
let ifSend = ref<boolean>(false)
//录音时长
let recordTime = ref<number>(0)
//录音设备实例
let rec: typeof Recorder | null = null
//波形显示实例
let wave: any = null
//波形绘制容器引用
let recwave = ref<HTMLDivElement | null>(null)
// 聊天消息对象
let reqmessage = reactive<messageFormData>({
    message_type: 'audio',
    conversation_id: messagesStore.chattingFriend?.conversation_id as number,
    sender_id: userStore.userId,
    receiver_id: messagesStore.chattingFriend?.userId as number,
    message_content: '',
    send_time: 0,
    media: null,
    media_url: null,
    duration: 0,
})

// 打开录音
function recOpen() {
    visible.value = true
    rec = Recorder({
        type: 'wav',
        sampleRate: 16000,
        bitRate: 16,
        onProcess(
            buffers: any[],
            powerLevel: number,
            _bufferDuration: number,
            bufferSampleRate: number,
        ) {
            if (wave) {
                wave.input(buffers[buffers.length - 1], powerLevel, bufferSampleRate)
            }
        },
    })

    if (!rec) {
        ElMessage.error('当前浏览器不支持录音功能！')
        return
    }

    // 打开录音并在成功后直接开始录音
    rec.open(
        () => {
            if (recwave.value) {
                wave = Recorder.WaveView({ elem: recwave.value })
            }
            rec.start() //录音设备准备好后直接开始录音
        },
        (msg: boolean, isUserNotAllow: string) => {
            ElMessage.error(`${isUserNotAllow ? '用户拒绝录音权限' : '无法录音'}: ${msg}`)
        },
    )
}

//取消录音
function recCancle() {
    ifSend.value = false
    recStop(ifSend.value)
    visible.value = false
}

// 结束录音
function recStop(ifSend: boolean): Promise<Blob | null> {
    return new Promise((resolve, reject) => {
        if (!rec) {
            resolve(null)
            return
        }
        rec.stop(
            (blob: Blob, duration: number) => {
                recordTime.value = Math.ceil(duration / 1000)
                rec.close()
                rec = null
                if (ifSend) {
                    resolve(blob)
                } else {
                    resolve(null)
                }
            },
            (err: any) => {
                ElMessage.error(`录音出错: ${err}`)
                rec.close()
                rec = null
                reject(err)
            },
        )
        visible.value = false
    })
}

// 发送语音消息
const sendVoice = async () => {
    visible.value = true
    ifSend.value = true
    const blob = await recStop(ifSend.value)

    if (!blob) {
        return ElMessage.error('录音失败')
    }

    //等待media赋值成功
    try {
        reqmessage.media = await readBlobAsBase64(blob)
    } catch (error) {
        return ElMessage.error('读取音频文件失败')
    }

    reqmessage.send_time = Date.now()
    reqmessage.message_content = `[语音]${recordTime.value}"`
    reqmessage.media_url = `/chatAppServer/audio/${reqmessage.conversation_id}-${v4()}.wav`
    reqmessage.duration = recordTime.value

    try {
        await messagesStore.sendMessage(reqmessage)
    } catch (error) {
        return ElMessage.error((error as Error).message)
    }

    if (webSocketStore.isConnected) {
        webSocketStore.sendMessage(reqmessage)
        //发送成功将消息存到本地和仓库中
        messagesStore.conversations = save(messagesStore.conversations, reqmessage)
        // 定义正则表达式来匹配文件名
        const regex = /\/chatAppServer\/audio\/([^/]+\.wav)$/
        // 使用正则表达式提取文件名
        const match = reqmessage.media_url.match(regex)
        const fileName = match![1]
        //将音频文件保存到本地
        await saveFile(reqmessage.message_type, blob, fileName)
    } else {
        return ElMessage({
            type: 'error',
            message: '网络未连接，请检查网络状态',
        })
    }
}

// 监听来电时停止录音
watch(
    () => webSocketStore.incomingCall,
    (newVal) => {
        if (newVal) {
            ifSend.value = false
            recStop(ifSend.value)
        }
    },
)
</script>

<style scoped lang="scss">
.el-popover {
    z-index: 4;
}

.el-progress--line {
    margin-bottom: 15px;
    max-width: 20rem;
}

.recWave {
    width: 10rem;
    height: 5rem;
}
</style>
